OpenGL/ES: Fix 'R' and 'B' bits inverted on Windows
authorChun-wei Fan <fanchunwei@src.gnome.org>
Tue, 31 Jul 2018 10:18:59 +0000 (18:18 +0800)
committerChun-wei Fan <fanchunwei@src.gnome.org>
Thu, 30 Jul 2020 06:30:13 +0000 (14:30 +0800)
We need to use GL_BGRA instead of GL_RGBA when doing glReadPixels() on
EGL on Windows (ANGLE) so that the red and blue bits won't be displayed
inverted.

Also fix the logic where we determine whether to bit blit or redraw
everything.

gdk/gdkgl.c
gdk/gdkglcontext.c
gdk/gdkglcontextprivate.h
gdk/win32/gdkglcontext-win32.c

index 6ea045b9b01dc961b5a739b6931b89491b806937..309f792613acf3123d0e8504a3ed49fca5c5d220 100644 (file)
@@ -334,6 +334,7 @@ gdk_cairo_draw_from_gl (cairo_t              *cr,
   cairo_region_t *clip_region;
   GdkGLContextPaintData *paint_data;
   int major, minor, version;
+  gboolean es_use_bgra = FALSE;
 
   paint_context = gdk_surface_get_paint_gl_context (surface, NULL);
   if (paint_context == NULL)
@@ -343,6 +344,7 @@ gdk_cairo_draw_from_gl (cairo_t              *cr,
     }
 
   clip_region = gdk_cairo_region_from_clip (cr);
+  es_use_bgra = gdk_gl_context_use_es_bgra (paint_context);
 
   gdk_gl_context_make_current (paint_context);
   paint_data = gdk_gl_context_get_paint_data (paint_context);
@@ -413,7 +415,7 @@ gdk_cairo_draw_from_gl (cairo_t              *cr,
     glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
                   cairo_image_surface_get_data (image));
   else
-    glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
+    glReadPixels (x, y, width, height, es_use_bgra ? GL_BGRA : GL_RGBA, GL_UNSIGNED_BYTE,
                   cairo_image_surface_get_data (image));
 
   glPixelStorei (GL_PACK_ROW_LENGTH, 0);
index 7e4554a6a18b38d75baae81acd3c7525084ed6cd..a7284b27c670dc4d8ebec2f42a480c6b3c3c79d2 100644 (file)
 #include "gdkintl.h"
 #include "gdk-private.h"
 
+#ifdef GDK_WINDOWING_WIN32
+# include "gdk/win32/gdkwin32.h"
+#endif
+
 #include <epoxy/gl.h>
 
 typedef struct {
@@ -1226,3 +1230,19 @@ gdk_gl_context_has_debug (GdkGLContext *self)
 
   return priv->debug_enabled || priv->use_khr_debug;
 }
+
+/* This is currently private! */
+/* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */
+gboolean
+gdk_gl_context_use_es_bgra (GdkGLContext *context)
+{
+  if (!gdk_gl_context_get_use_es (context))
+    return FALSE;
+
+#ifdef GDK_WINDOWING_WIN32
+  if (GDK_WIN32_IS_GL_CONTEXT (context))
+    return TRUE;
+#endif
+
+  return FALSE;
+}
index c289c144f39c4063e980f06172adaf2aaf0b02c9..bf2dbfa5ff0f851e67fc135ab0054dad4471b4cc 100644 (file)
@@ -107,6 +107,9 @@ void                    gdk_gl_context_label_object_printf      (GdkGLContext
                                                                 ...)  G_GNUC_PRINTF (4, 5);
 
 gboolean                gdk_gl_context_has_debug                (GdkGLContext    *self) G_GNUC_PURE;
+
+gboolean                gdk_gl_context_use_es_bgra              (GdkGLContext    *context);
+
 G_END_DECLS
 
 #endif /* __GDK_GL_CONTEXT_PRIVATE_H__ */
index 6fffbc38e57be07e673dfbd35a5558592c1c418b..d52c16e2cbd8cd0b18de535408de9b550bc2c8ad 100644 (file)
@@ -213,9 +213,7 @@ gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context,
       EGLSurface egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, FALSE);
       gboolean force_egl_redraw_all = _get_is_egl_force_redraw (surface);
 
-         if (!force_egl_redraw_all)
-        gdk_gl_blit_region (surface, painted);
-      else if (force_egl_redraw_all)
+         if (force_egl_redraw_all)
         {
           GdkRectangle rect = {0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface)};
 
@@ -226,7 +224,15 @@ gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context,
           _reset_egl_force_redraw (surface);
         }
 
-      eglSwapBuffers (display->egl_disp, egl_surface);
+      if (cairo_region_contains_rectangle (painted, &whole_window) == CAIRO_REGION_OVERLAP_IN || force_egl_redraw_all)
+        eglSwapBuffers (display->egl_disp, egl_surface);
+      else if (gdk_gl_context_has_framebuffer_blit (context))
+        gdk_gl_blit_region (surface, painted);
+      else
+        {
+          g_warning ("Need to swap whole buffer even thouigh not everything was redrawn. Expect artifacts.");
+          eglSwapBuffers (display->egl_disp, egl_surface);
+        }
     }
 #endif
 }